{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "69032b4b-b031-4020-beb0-e8dfd22b660e",
   "metadata": {},
   "source": [
    "# LangChain 实战：销售聊天机器人"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "efcee928-b9f4-4e4a-b9fb-f6cbee21b642",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"育儿专家问答100.txt\",'r', encoding='utf-8') as f:\n",
    "    content = f.read()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a9119556-d2e3-4edf-be16-15837da156f1",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "source": [
    "### 使用 CharacterTextSplitter 来进行文本分割\n",
    "\n",
    "- 基于单字符来进行文本分割（separator）\n",
    "- 基于字符数来决定文本块长度（chunk_size）\n",
    "\n",
    "参考示例：\n",
    "\n",
    "```python\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "text_splitter = CharacterTextSplitter(        \n",
    "    separator = \"\\n\\n\",\n",
    "    chunk_size = 1000,\n",
    "    chunk_overlap  = 200,\n",
    "    length_function = len,\n",
    "    is_separator_regex = False,\n",
    ")\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "dbe535b8-2bd8-4c31-91d7-eba8aa61b3ef",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.text_splitter import CharacterTextSplitter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a4f30d9b-9fc6-4860-a497-0aa8220b9284",
   "metadata": {},
   "outputs": [],
   "source": [
    "text_splitter = CharacterTextSplitter(        \n",
    "    separator = r'\\d+\\.',\n",
    "    chunk_size = 100,\n",
    "    chunk_overlap  = 0,\n",
    "    length_function = len,\n",
    "    is_separator_regex = True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "530f3172-17a5-4924-ad17-284fbca422ae",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 175, which is longer than the specified 100\n",
      "Created a chunk of size 109, which is longer than the specified 100\n",
      "Created a chunk of size 102, which is longer than the specified 100\n",
      "Created a chunk of size 111, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 102, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 122, which is longer than the specified 100\n",
      "Created a chunk of size 115, which is longer than the specified 100\n",
      "Created a chunk of size 164, which is longer than the specified 100\n",
      "Created a chunk of size 128, which is longer than the specified 100\n",
      "Created a chunk of size 129, which is longer than the specified 100\n",
      "Created a chunk of size 144, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 102, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 102, which is longer than the specified 100\n",
      "Created a chunk of size 118, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 144, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 128, which is longer than the specified 100\n",
      "Created a chunk of size 120, which is longer than the specified 100\n",
      "Created a chunk of size 111, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 144, which is longer than the specified 100\n",
      "Created a chunk of size 118, which is longer than the specified 100\n",
      "Created a chunk of size 108, which is longer than the specified 100\n",
      "Created a chunk of size 105, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 119, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 104, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 115, which is longer than the specified 100\n",
      "Created a chunk of size 128, which is longer than the specified 100\n",
      "Created a chunk of size 119, which is longer than the specified 100\n",
      "Created a chunk of size 109, which is longer than the specified 100\n",
      "Created a chunk of size 103, which is longer than the specified 100\n",
      "Created a chunk of size 120, which is longer than the specified 100\n",
      "Created a chunk of size 115, which is longer than the specified 100\n",
      "Created a chunk of size 115, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 144, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 105, which is longer than the specified 100\n",
      "Created a chunk of size 102, which is longer than the specified 100\n",
      "Created a chunk of size 113, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 104, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 115, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 132, which is longer than the specified 100\n",
      "Created a chunk of size 109, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 112, which is longer than the specified 100\n",
      "Created a chunk of size 104, which is longer than the specified 100\n",
      "Created a chunk of size 109, which is longer than the specified 100\n",
      "Created a chunk of size 103, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 105, which is longer than the specified 100\n",
      "Created a chunk of size 103, which is longer than the specified 100\n",
      "Created a chunk of size 113, which is longer than the specified 100\n",
      "Created a chunk of size 165, which is longer than the specified 100\n",
      "Created a chunk of size 127, which is longer than the specified 100\n",
      "Created a chunk of size 115, which is longer than the specified 100\n",
      "Created a chunk of size 102, which is longer than the specified 100\n",
      "Created a chunk of size 125, which is longer than the specified 100\n",
      "Created a chunk of size 134, which is longer than the specified 100\n",
      "Created a chunk of size 120, which is longer than the specified 100\n",
      "Created a chunk of size 129, which is longer than the specified 100\n",
      "Created a chunk of size 120, which is longer than the specified 100\n",
      "Created a chunk of size 122, which is longer than the specified 100\n",
      "Created a chunk of size 144, which is longer than the specified 100\n",
      "Created a chunk of size 132, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 124, which is longer than the specified 100\n",
      "Created a chunk of size 104, which is longer than the specified 100\n",
      "Created a chunk of size 130, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 124, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 125, which is longer than the specified 100\n",
      "Created a chunk of size 127, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 131, which is longer than the specified 100\n",
      "Created a chunk of size 118, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 108, which is longer than the specified 100\n",
      "Created a chunk of size 128, which is longer than the specified 100\n",
      "Created a chunk of size 112, which is longer than the specified 100\n",
      "Created a chunk of size 102, which is longer than the specified 100\n",
      "Created a chunk of size 125, which is longer than the specified 100\n",
      "Created a chunk of size 139, which is longer than the specified 100\n",
      "Created a chunk of size 111, which is longer than the specified 100\n",
      "Created a chunk of size 118, which is longer than the specified 100\n",
      "Created a chunk of size 121, which is longer than the specified 100\n",
      "Created a chunk of size 113, which is longer than the specified 100\n",
      "Created a chunk of size 117, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 113, which is longer than the specified 100\n",
      "Created a chunk of size 103, which is longer than the specified 100\n",
      "Created a chunk of size 141, which is longer than the specified 100\n",
      "Created a chunk of size 131, which is longer than the specified 100\n",
      "Created a chunk of size 118, which is longer than the specified 100\n",
      "Created a chunk of size 108, which is longer than the specified 100\n",
      "Created a chunk of size 120, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 132, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 105, which is longer than the specified 100\n",
      "Created a chunk of size 124, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 104, which is longer than the specified 100\n",
      "Created a chunk of size 134, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 115, which is longer than the specified 100\n",
      "Created a chunk of size 130, which is longer than the specified 100\n",
      "Created a chunk of size 126, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 105, which is longer than the specified 100\n",
      "Created a chunk of size 123, which is longer than the specified 100\n",
      "Created a chunk of size 127, which is longer than the specified 100\n",
      "Created a chunk of size 104, which is longer than the specified 100\n",
      "Created a chunk of size 133, which is longer than the specified 100\n",
      "Created a chunk of size 119, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 136, which is longer than the specified 100\n",
      "Created a chunk of size 133, which is longer than the specified 100\n",
      "Created a chunk of size 123, which is longer than the specified 100\n",
      "Created a chunk of size 105, which is longer than the specified 100\n",
      "Created a chunk of size 115, which is longer than the specified 100\n",
      "Created a chunk of size 119, which is longer than the specified 100\n",
      "Created a chunk of size 132, which is longer than the specified 100\n",
      "Created a chunk of size 124, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 109, which is longer than the specified 100\n",
      "Created a chunk of size 118, which is longer than the specified 100\n",
      "Created a chunk of size 113, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 124, which is longer than the specified 100\n",
      "Created a chunk of size 111, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 126, which is longer than the specified 100\n",
      "Created a chunk of size 111, which is longer than the specified 100\n",
      "Created a chunk of size 152, which is longer than the specified 100\n",
      "Created a chunk of size 126, which is longer than the specified 100\n",
      "Created a chunk of size 118, which is longer than the specified 100\n",
      "Created a chunk of size 101, which is longer than the specified 100\n",
      "Created a chunk of size 110, which is longer than the specified 100\n",
      "Created a chunk of size 119, which is longer than the specified 100\n",
      "Created a chunk of size 104, which is longer than the specified 100\n",
      "Created a chunk of size 113, which is longer than the specified 100\n",
      "Created a chunk of size 102, which is longer than the specified 100\n",
      "Created a chunk of size 132, which is longer than the specified 100\n",
      "Created a chunk of size 136, which is longer than the specified 100\n",
      "Created a chunk of size 124, which is longer than the specified 100\n",
      "Created a chunk of size 109, which is longer than the specified 100\n",
      "Created a chunk of size 106, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 119, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 124, which is longer than the specified 100\n",
      "Created a chunk of size 132, which is longer than the specified 100\n",
      "Created a chunk of size 135, which is longer than the specified 100\n",
      "Created a chunk of size 138, which is longer than the specified 100\n",
      "Created a chunk of size 122, which is longer than the specified 100\n",
      "Created a chunk of size 116, which is longer than the specified 100\n",
      "Created a chunk of size 126, which is longer than the specified 100\n",
      "Created a chunk of size 105, which is longer than the specified 100\n",
      "Created a chunk of size 112, which is longer than the specified 100\n",
      "Created a chunk of size 120, which is longer than the specified 100\n",
      "Created a chunk of size 111, which is longer than the specified 100\n",
      "Created a chunk of size 105, which is longer than the specified 100\n",
      "Created a chunk of size 107, which is longer than the specified 100\n",
      "Created a chunk of size 111, which is longer than the specified 100\n",
      "Created a chunk of size 108, which is longer than the specified 100\n",
      "Created a chunk of size 104, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 112, which is longer than the specified 100\n",
      "Created a chunk of size 111, which is longer than the specified 100\n",
      "Created a chunk of size 138, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 114, which is longer than the specified 100\n",
      "Created a chunk of size 119, which is longer than the specified 100\n",
      "Created a chunk of size 119, which is longer than the specified 100\n",
      "Created a chunk of size 132, which is longer than the specified 100\n",
      "Created a chunk of size 122, which is longer than the specified 100\n"
     ]
    }
   ],
   "source": [
    "docs = text_splitter.create_documents([content])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "3956ec36-706e-4f43-88fc-d704f2984290",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Document(page_content='[育儿问题]：刚出生的孩子，家长怎样进行保暖？\\n   [专家回答]：新生儿易散热，需注意保暖。根据季节调整衣物，保持体温36-37℃。通过触摸后背和颈后判断温度，适时增减衣物。')"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "docs[490]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "73b2d47a-27ae-4cd4-a72a-3809b4c22bff",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "493"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(docs)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4617858-ad9c-42eb-a4c3-6bfb7108cdd2",
   "metadata": {},
   "source": [
    "### 使用 Faiss 作为向量数据库，持久化存储房产销售 问答对（QA-Pair）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "59f1cf46-2cda-4fcf-8235-ccb6ccd2743c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Requirement already satisfied: langchain-openai in d:\\miniconda\\lib\\site-packages (0.0.5)\n",
      "Requirement already satisfied: langchain-core<0.2,>=0.1.16 in d:\\miniconda\\lib\\site-packages (from langchain-openai) (0.1.22)\n",
      "Collecting numpy<2,>=1 (from langchain-openai)\n",
      "  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/3f/6b/5610004206cf7f8e7ad91c5a85a8c71b2f2f8051a0c0c4d5916b76d6cbb2/numpy-1.26.4-cp311-cp311-win_amd64.whl (15.8 MB)\n",
      "Requirement already satisfied: openai<2.0.0,>=1.10.0 in d:\\miniconda\\lib\\site-packages (from langchain-openai) (1.12.0)\n",
      "Requirement already satisfied: tiktoken<0.6.0,>=0.5.2 in d:\\miniconda\\lib\\site-packages (from langchain-openai) (0.5.2)\n",
      "Requirement already satisfied: PyYAML>=5.3 in d:\\miniconda\\lib\\site-packages (from langchain-core<0.2,>=0.1.16->langchain-openai) (6.0.1)\n",
      "Requirement already satisfied: anyio<5,>=3 in d:\\miniconda\\lib\\site-packages (from langchain-core<0.2,>=0.1.16->langchain-openai) (4.2.0)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in d:\\miniconda\\lib\\site-packages (from langchain-core<0.2,>=0.1.16->langchain-openai) (1.33)\n",
      "Requirement already satisfied: langsmith<0.0.88,>=0.0.87 in d:\\miniconda\\lib\\site-packages (from langchain-core<0.2,>=0.1.16->langchain-openai) (0.0.87)\n",
      "Requirement already satisfied: packaging<24.0,>=23.2 in d:\\miniconda\\lib\\site-packages (from langchain-core<0.2,>=0.1.16->langchain-openai) (23.2)\n",
      "Requirement already satisfied: pydantic<3,>=1 in d:\\miniconda\\lib\\site-packages (from langchain-core<0.2,>=0.1.16->langchain-openai) (2.6.1)\n",
      "Requirement already satisfied: requests<3,>=2 in d:\\miniconda\\lib\\site-packages (from langchain-core<0.2,>=0.1.16->langchain-openai) (2.31.0)\n",
      "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in d:\\miniconda\\lib\\site-packages (from langchain-core<0.2,>=0.1.16->langchain-openai) (8.2.3)\n",
      "Requirement already satisfied: distro<2,>=1.7.0 in d:\\miniconda\\lib\\site-packages (from openai<2.0.0,>=1.10.0->langchain-openai) (1.8.0)\n",
      "Requirement already satisfied: httpx<1,>=0.23.0 in d:\\miniconda\\lib\\site-packages (from openai<2.0.0,>=1.10.0->langchain-openai) (0.26.0)\n",
      "Requirement already satisfied: sniffio in d:\\miniconda\\lib\\site-packages (from openai<2.0.0,>=1.10.0->langchain-openai) (1.3.0)\n",
      "Requirement already satisfied: tqdm>4 in d:\\miniconda\\lib\\site-packages (from openai<2.0.0,>=1.10.0->langchain-openai) (4.65.0)\n",
      "Requirement already satisfied: typing-extensions<5,>=4.7 in d:\\miniconda\\lib\\site-packages (from openai<2.0.0,>=1.10.0->langchain-openai) (4.9.0)\n",
      "Requirement already satisfied: regex>=2022.1.18 in d:\\miniconda\\lib\\site-packages (from tiktoken<0.6.0,>=0.5.2->langchain-openai) (2023.12.25)\n",
      "Requirement already satisfied: idna>=2.8 in d:\\miniconda\\lib\\site-packages (from anyio<5,>=3->langchain-core<0.2,>=0.1.16->langchain-openai) (3.4)\n",
      "Requirement already satisfied: certifi in d:\\miniconda\\lib\\site-packages (from httpx<1,>=0.23.0->openai<2.0.0,>=1.10.0->langchain-openai) (2023.11.17)\n",
      "Requirement already satisfied: httpcore==1.* in d:\\miniconda\\lib\\site-packages (from httpx<1,>=0.23.0->openai<2.0.0,>=1.10.0->langchain-openai) (1.0.2)\n",
      "Requirement already satisfied: h11<0.15,>=0.13 in d:\\miniconda\\lib\\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai<2.0.0,>=1.10.0->langchain-openai) (0.14.0)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in d:\\miniconda\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain-core<0.2,>=0.1.16->langchain-openai) (2.1)\n",
      "Requirement already satisfied: annotated-types>=0.4.0 in d:\\miniconda\\lib\\site-packages (from pydantic<3,>=1->langchain-core<0.2,>=0.1.16->langchain-openai) (0.6.0)\n",
      "Requirement already satisfied: pydantic-core==2.16.2 in d:\\miniconda\\lib\\site-packages (from pydantic<3,>=1->langchain-core<0.2,>=0.1.16->langchain-openai) (2.16.2)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in d:\\miniconda\\lib\\site-packages (from requests<3,>=2->langchain-core<0.2,>=0.1.16->langchain-openai) (2.0.4)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in d:\\miniconda\\lib\\site-packages (from requests<3,>=2->langchain-core<0.2,>=0.1.16->langchain-openai) (1.26.18)\n",
      "Requirement already satisfied: colorama in d:\\miniconda\\lib\\site-packages (from tqdm>4->openai<2.0.0,>=1.10.0->langchain-openai) (0.4.6)\n",
      "Installing collected packages: numpy\n",
      "Successfully installed numpy-1.26.4\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Requirement already satisfied: numpy in d:\\miniconda\\lib\\site-packages (1.26.4)\n",
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple\n",
      "Requirement already satisfied: faiss-cpu in d:\\miniconda\\lib\\site-packages (1.7.4)\n"
     ]
    }
   ],
   "source": [
    "!pip install -U langchain-openai\n",
    "!pip install -U numpy\n",
    "!pip install -U faiss-cpu"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64aa6134-aa74-4cfb-82b1-7ade44981ecc",
   "metadata": {},
   "outputs": [],
   "source": [
    "pip uninstall numpy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "508c2ab2-e187-424f-a43c-ca3d3b1a0550",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "from langchain.vectorstores import FAISS\n",
    "\n",
    "db = FAISS.from_documents(docs, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "250e0873-95e2-4372-98a5-68c0feb304bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "query = \"如何抱宝宝\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0d18fcc6-c2be-434b-b8de-9648ac6f83f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在数据库中查找与给定查询最相似的文档条目\n",
    "answer_list = db.similarity_search(query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e689667e-7a45-40d6-9eae-4e52cbc7daab",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[育儿问题]：抱宝宝不能摇晃？\n",
      "   [专家回答]：避免强烈摇晃，以防“婴儿摇晃综合征”。应采用轻柔动作。\n",
      "\n",
      "[育儿问题]：抱宝宝不能摇晃？\n",
      "   [专家回答]：因为过于强烈的动作会伤害宝宝的大脑，使宝宝患上“婴儿摇晃综合征”，特别是6个月以内的宝宝，严重会导致宝宝脑出血和脑震荡。总之，怀抱、哄睡都应该选择轻柔小幅的动作。\n",
      "\n",
      "[育儿问题]：新生儿哭泣时会摆脱我抱着的姿势，这正常吗？\n",
      "    [专家回答]：宝宝哭泣时可能会有力地摆动手脚，试图表达不适。在抱宝宝时，确保支撑宝宝的头部和颈部，并轻柔安抚。如果你认为宝宝的哭泣可能是因为不适，请仔细检查并咨询医生。\n",
      "\n",
      "[育儿问题]：宝宝夜间哭闹不止，如何安抚？\n",
      "    [专家回答]：首先检查宝宝是否因为饥饿、尿布湿、温度不适或疾病等原因哭闹。如果排除了这些原因，可以尝试轻柔地摇晃、唱歌或安抚宝宝，有时持续的安抚可以帮助宝宝重新入睡。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for ans in answer_list:\n",
    "    print(ans.page_content + \"\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "a6cc47bf-1566-472f-84d2-a46bd634907c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 持久化数据库内容\n",
    "db.save_local(\"parenting Q&A\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d5323e5-03fa-4c1c-b896-3ccc28af1857",
   "metadata": {},
   "source": [
    "### 使用 retriever 从向量数据库中获取结果"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b335c9e5-bc01-4a47-916c-03bec0e7a839",
   "metadata": {},
   "source": [
    "#### 使用 similarity_score_threshold 设置阈值，提升结果的相关性质量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "b1298956-6cf3-4a68-a3c2-a3149f64f156",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 实例化一个 similarity_score_threshold Retriever\n",
    "retriever = db.as_retriever(\n",
    "    search_type=\"similarity_score_threshold\",\n",
    "    search_kwargs={\"score_threshold\": 0.8}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "d61167de-72ed-4618-a2e1-5df04784a3bc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[育儿问题]：宝宝咳嗽怎么办？\n",
      "    [专家回答]：保持室内空气湿润，多给宝宝喝水。若咳嗽症状严重，应及时就医，遵医嘱使用药物。\n",
      "\n",
      "[育儿问题]：如何处理宝宝的轻微咳嗽症状？\n",
      "    [专家回答]：保持宝宝充分休息，提供充足的水分。如果咳嗽症状严重，应及时就医，遵医嘱使用药物。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "docs = retriever.get_relevant_documents(query)\n",
    "for doc in docs:\n",
    "    print(doc.page_content + \"\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "548d1b52-6fa2-46d6-9218-908db572f380",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "c31344ce-f952-4604-b700-fdbb34da1e28",
   "metadata": {},
   "source": [
    "### 提取向量数据库中的回答"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "25768463-da65-4762-978d-51c0c3a9c24b",
   "metadata": {},
   "outputs": [],
   "source": [
    "docs = retriever.get_relevant_documents(query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "4838d3da-dca3-4c31-80da-cec75760a833",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'[育儿问题]：抱宝宝不能摇晃？\\n   [专家回答]：避免强烈摇晃，以防“婴儿摇晃综合征”。应采用轻柔动作。'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "docs[0].page_content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "1ba30232-f468-4102-b70c-02c8b74da43d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['[育儿问题]：抱宝宝不能摇晃？\\n   ', '避免强烈摇晃，以防“婴儿摇晃综合征”。应采用轻柔动作。']"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "docs[0].page_content.split(\"[专家回答]：\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "bda8eb0c-eb1f-47b2-91ab-4c94ff71c3db",
   "metadata": {},
   "outputs": [],
   "source": [
    "ans = docs[0].page_content.split(\"[专家回答]：\")[-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "917a3b6c-3149-42e2-b7b6-abebd94b7f72",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'避免强烈摇晃，以防“婴儿摇晃综合征”。应采用轻柔动作。'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ans"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b36b61a5-156d-4546-bbd1-8a983e94676b",
   "metadata": {},
   "source": [
    "#### 尝试各种问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "c311a656-e571-45d6-8690-88e4be2c2a65",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "\n",
    "def sales(query: str, score_threshold: float=0.8) -> List[str]:\n",
    "    retriever = db.as_retriever(search_type=\"similarity_score_threshold\", search_kwargs={\"score_threshold\": score_threshold})    \n",
    "    docs = retriever.get_relevant_documents(query)\n",
    "    ans_list = [doc.page_content.split(\"[专家回答]：\")[-1] for doc in docs]\n",
    "\n",
    "    return ans_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "2f4c6c08-b97c-4727-9aa1-a474d85a11e4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['保持室内空气湿润，多给宝宝喝水。若咳嗽症状严重，应及时就医，遵医嘱使用药物。', '保持宝宝充分休息，提供充足的水分。如果咳嗽症状严重，应及时就医，遵医嘱使用药物。', '孕期前三个月，孕妈妈尤其要做好感冒的预防工作，如佩戴口罩，尽量减少出入公共场所，增强自身抵抗力。如果患上感冒，要尽量多休息、多喝温水，清淡饮食，多吃新鲜果蔬。三个月后（致畸风险减低）可在医师指导下用药。', '保持适当的休息，避免过度劳累，适当进行放松训练，如深呼吸、冥想等。']\n"
     ]
    }
   ],
   "source": [
    "query = \"孕妇咳嗽怎么办\"\n",
    "\n",
    "print(sales(query))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "11e3d8b6-839f-4b2f-b519-841e0271f95b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['保持室内空气湿润，多给宝宝喝水。若咳嗽症状严重，应及时就医，遵医嘱使用药物。', '保持宝宝充分休息，提供充足的水分。如果咳嗽症状严重，应及时就医，遵医嘱使用药物。', '使用婴儿专用的盐水滴鼻剂或喷雾来缓解宝宝的鼻塞。如果宝宝太小，可以使用吸鼻器轻轻吸出鼻涕。保持室内空气湿润，有助于减少鼻塞。', '保持宝宝充分休息，提供充足的水分和营养。如果宝宝有发烧、呼吸困难或症状持续，应立即就医。']\n"
     ]
    }
   ],
   "source": [
    "print(sales(query, 0.75))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "fc5b030a-ae6f-4d42-9577-1420c78aecb1",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\gwk\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\langchain_core\\vectorstores.py:323: UserWarning: No relevant docs were retrieved using the relevance score threshold 0.8\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score:0.8 ans: []\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\gwk\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\langchain_core\\vectorstores.py:323: UserWarning: No relevant docs were retrieved using the relevance score threshold 0.75\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score:0.75 ans: []\n",
      "\n",
      "score:0.5 ans: ['是的，定期体检对于监测新生儿的健康和发育非常重要。在头几周和头几个月里，儿科医生会安排几次检查，以确保宝宝的成长、发育和营养状况良好。', '这是正常现象。所谓的“假月经”是由母体激素影响造成的，通常几天后自行停止。新生儿乳腺肿大也是常见的，不需特殊处理。若有异常症状，应咨询医生。', '这是“假月经”，受妈妈体内雌激素影响，通常5-7天后自行停止。', '定期进行产前检查以监测宝宝的发育情况。保持均衡饮食，摄入足够的营养素，保持适当的体重增长。避免吸烟、饮酒和接触有害物质。充分休息，管理好压力。']\n",
      "\n"
     ]
    }
   ],
   "source": [
    "query = \"月子中心\"\n",
    "\n",
    "print(f\"score:0.8 ans: {sales(query)}\\n\")\n",
    "print(f\"score:0.75 ans: {sales(query, 0.75)}\\n\")\n",
    "print(f\"score:0.5 ans: {sales(query, 0.5)}\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e26e6d7-259b-4ecf-9c72-027befba4e3b",
   "metadata": {},
   "source": [
    "#### 当向量数据库中没有合适答案时，使用大语言模型能力\n",
    "创建了一个QA_chain，它先通过一个检索器(retriever)从一个向量数据库中找到与问题相似度高于0.8的文档，\n",
    "然后使用一个语言模型来基于这些文档生成或精炼答案。\n",
    "\n",
    "这种方法结合了检索和生成的优势，既能利用大量的信息源，又能通过语言模型的理解和生成能力提供准确和具有上下文关联的答案。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "178bba7c-047d-4355-b593-2ab338b4bc9c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "os.environ[\"http_proxy\"] = \"http://127.0.0.1:33210\"\n",
    "os.environ[\"https_proxy\"] = \"http://127.0.0.1:33210\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "9142feb4-980a-4142-b367-1401021dceef",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "llm = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0.5)\n",
    "qa_chain = RetrievalQA.from_chain_type(llm,\n",
    "                                       retriever=db.as_retriever(search_type=\"similarity_score_threshold\",\n",
    "                                                                 search_kwargs={\"score_threshold\": 0.8}))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "d281b560-54bb-4a25-a1dc-b23874361654",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'query': '孕妇咳嗽怎么办？',\n",
       " 'result': '孕妇咳嗽的处理方法与一般的咳嗽处理方法相似。首先，保持室内空气湿润，可以使用加湿器或放置湿毛巾来增加空气湿度。其次，多喝温水，保持充足的水分摄入。此外，孕妇应该避免吸烟和接触有害气体，保持良好的卫生习惯，如勤洗手等。如果咳嗽症状严重或持续时间较长，建议及时就医，遵医嘱使用药物。'}"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qa_chain.invoke({\"query\": \"孕妇咳嗽怎么办？\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "9da44bd6-02ef-4fb6-8e9e-7c99aeba483a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['保持室内空气湿润，多给宝宝喝水。若咳嗽症状严重，应及时就医，遵医嘱使用药物。', '保持宝宝充分休息，提供充足的水分。如果咳嗽症状严重，应及时就医，遵医嘱使用药物。', '孕期前三个月，孕妈妈尤其要做好感冒的预防工作，如佩戴口罩，尽量减少出入公共场所，增强自身抵抗力。如果患上感冒，要尽量多休息、多喝温水，清淡饮食，多吃新鲜果蔬。三个月后（致畸风险减低）可在医师指导下用药。', '保持适当的休息，避免过度劳累，适当进行放松训练，如深呼吸、冥想等。']\n"
     ]
    }
   ],
   "source": [
    "# 直接检索没有数据\n",
    "print(sales(\"孕妇咳嗽怎么办？\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9764bb10-44ed-47c9-a351-a68f4f7d4f44",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "0a0647e8-5b41-4c93-87c2-3240ec558717",
   "metadata": {},
   "source": [
    "## 加载 FAISS 向量数据库已有结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "913edd04-37ea-4c3f-9346-086aeb0ab447",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain.vectorstores import FAISS\n",
    "\n",
    "db = FAISS.load_local(\"parenting Q&A\", OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "77d8eee4-6383-4b4a-9737-95ea9fc53b87",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "llm = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0.5)\n",
    "qa_chain = RetrievalQA.from_chain_type(llm,\n",
    "                                       retriever=db.as_retriever(search_type=\"similarity_score_threshold\",\n",
    "                                                                 search_kwargs={\"score_threshold\": 0.8}))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "fc393afc-06d3-4483-bd24-efe000ef5f2a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 输出内部 Chain 的日志\n",
    "qa_chain.combine_documents_chain.verbose = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "013c313a-5e7c-48d1-8ed4-eee96e50a99c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\gwk\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\langchain_core\\vectorstores.py:323: UserWarning: No relevant docs were retrieved using the relevance score threshold 0.8\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new StuffDocumentsChain chain...\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'query': '月子中心怎么选',\n",
       " 'result': '选择月子中心需要考虑以下几个方面：\\n\\n1. 地理位置：选择一个离家近的月子中心，方便家人探望和照顾。\\n\\n2. 设施设备：了解月子中心的房间、浴室、厨房等设施是否齐全，并且是否有专业的月嫂和医护人员提供服务。\\n\\n3. 服务项目：了解月子中心提供的服务项目，如产后康复、母婴护理、营养餐等，选择适合自己需求的。\\n\\n4. 价格和费用：了解月子中心的收费标准和包含的服务项目，确保自己能够负担得起。\\n\\n5. 口碑和评价：可以通过亲友的推荐或者在网上查阅其他用户的评价，了解月子中心的口碑和服务质量。\\n\\n最重要的是根据自己的需求和预算进行选择，可以提前多了解几个月子中心，进行比较后再做决定。'}"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qa_chain.invoke({\"query\": \"孕妇咳嗽怎么办\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "e5fb0943-ffe9-4270-8dbe-f5f5314e6042",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 返回向量数据库的检索结果\n",
    "qa_chain.return_source_documents = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "fbc1741e-d34f-4df5-874b-02b78e8cd67a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new StuffDocumentsChain chain...\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "result = qa_chain.invoke({\"query\": \"孕妇咳嗽怎么办\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "fac8309c-033c-4144-ada0-08e74fa9bf2d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'query': '孕妇咳嗽怎么办',\n",
       " 'result': '[专家回答]：孕妇咳嗽时，可以尝试以下方法缓解症状：\\n1. 保持室内空气湿润，可以使用加湿器或放置湿毛巾。\\n2. 多喝温水，保持身体水分充足。\\n3. 适当休息，避免过度劳累。\\n4. 可以尝试用温水漱口或含漱喉咙，缓解咳嗽。\\n5. 饮食上选择清淡易消化的食物，多吃新鲜水果和蔬菜。\\n6. 如果症状严重或持续时间较长，建议及时就医，遵医嘱使用药物。\\n\\n请注意，以上建议仅供参考，具体治疗方法还需根据个体情况和医生的指导进行。',\n",
       " 'source_documents': [Document(page_content='[育儿问题]：宝宝咳嗽怎么办？\\n    [专家回答]：保持室内空气湿润，多给宝宝喝水。若咳嗽症状严重，应及时就医，遵医嘱使用药物。'),\n",
       "  Document(page_content='[育儿问题]：如何处理宝宝的轻微咳嗽症状？\\n    [专家回答]：保持宝宝充分休息，提供充足的水分。如果咳嗽症状严重，应及时就医，遵医嘱使用药物。'),\n",
       "  Document(page_content='[孕妇问题]：孕期感冒怎么办？\\n   [专家回答]：孕期前三个月，孕妈妈尤其要做好感冒的预防工作，如佩戴口罩，尽量减少出入公共场所，增强自身抵抗力。如果患上感冒，要尽量多休息、多喝温水，清淡饮食，多吃新鲜果蔬。三个月后（致畸风险减低）可在医师指导下用药。'),\n",
       "  Document(page_content='[孕妇问题]：孕期如何应对孕期呼吸困难？\\n    [专家回答]：保持适当的休息，避免过度劳累，适当进行放松训练，如深呼吸、冥想等。')]}"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37de84df-999f-4469-9bbe-de9c95c6f6b3",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
